﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Video;
using DanMuHelper.Pool;

namespace DanMuHelper.Video
{
    public abstract class BaseMediaPlayerData
    {
        // 在这里添加任何所有媒体播放器共享的数据字段
    }

    public class VideoPlayerMediaData : BaseMediaPlayerData
    {
        public AudioClip AudioClip;
        public VideoClip VideoClip;
    }

    //public interface IMediaPlayer<MediaPlayerData> where MediaPlayerData : BaseMediaPlayerData
    public interface IMediaPlayer
    {
        //void Schedule(IVideoContext context, MediaPlayerData mediaPlayerData);
        void Schedule(IVideoContext context, BaseMediaPlayerData mediaPlayerData);
        void StopAndUnscheduleAll();
        void ChangeMediaPlaySpeed(float targetSpeed);
    }

    public abstract class BaseMediaPlayer/*<MediaPlayerData>*/
         : MonoBehaviour, IMediaPlayer/*<MediaPlayerData> where MediaPlayerData : BaseMediaPlayerData*/
    {

        /// <summary>
        /// 任务合并
        /// </summary>
        protected class PlayData
        {
            //public VideoClip VideoClip;
            //public AudioClip AudioClip;

            public BaseMediaPlayerData videoData;
            public readonly List<IVideoContext> Items = new List<IVideoContext>();
            private int _totalScalarValue;
            private int _totalWeightValue;
            public int TotalScalarValue => _totalScalarValue;
            public int TotalWeightValue => _totalWeightValue;

            public static void Reset(PlayData target)
            {
                target.videoData = null;
                //target.VideoClip = null;
                //target.AudioClip = null;
                target.Items.Clear();
                target._totalScalarValue = 0;
            }

            public void Add(IVideoContext item)
            {
                Items.Add(item);
                _totalScalarValue += item.ScalarValue;
                _totalWeightValue += item.Weight;
            }
        }

        /// <summary>
        /// 播放结束后是否保留视频
        /// </summary>
        [Header("播放结束后是否保留视频")]
        public bool KeepVideoClip = false;

        /// <summary>
        /// 播放间隔
        /// </summary>
        [Header("播放间隔")]
        public float playInterval = 0.0f;

        /// <summary>
        /// 开始播放事件, 此时视频还没有播放, 仅仅调用了VideoPlayer.Play
        /// </summary>
        public UnityEvent<BaseMediaPlayer, IReadOnlyList<IVideoContext>, int> onVideoWillPlay = new();

        /// <summary>
        /// Video prepared, and play started
        /// </summary>
        public UnityEvent<BaseMediaPlayer, IReadOnlyList<IVideoContext>, int> onVideoPlayStarted = new();

        /// <summary>
        /// 播放结束事件, 参数(VideoController, 回传参数, 合并数量)
        /// </summary>
        public UnityEvent<BaseMediaPlayer, IReadOnlyList<IVideoContext>, int> onVideoPlayComplete = new();

        /// <summary>
        /// VideoPlayer.Play接口是否已经调用 (注意: 调用时, 视频并没有真实开始)
        /// </summary>
        public bool IsPlayerStarted { get; protected set; }

        [ShowInInspectorAttribute]
        protected float _lastPlayEndTime;

        [ShowInInspectorAttribute]
        protected float _videoPrepareTime;

        [ShowInInspectorAttribute]
        private bool _isInited;

        [ShowInInspectorAttribute]
        protected LinkedList<PlayData> _playQueue = new LinkedList<PlayData>();

        protected Pool<PlayData> _playDataPool = null;

        protected PlayData _cursor = null;

        /// <summary>
        /// 当前队列长度
        /// </summary>
        public int CountScheduled => _playQueue.Count;

        /// <summary>
        /// 互斥播放器, 当列表不为空时, 不能播放
        /// </summary>
        protected List<IMediaPlayer> _mutexControllers = new List<IMediaPlayer>(8);

        public void AddMutex(IMediaPlayer other)
        {
            if ((object)other == this)
            {
                Debug.LogError("VideoController is same");
                return;
            }
            if (!_mutexControllers.Contains(other))
            {
                _mutexControllers.Add(other);
            }
        }

        public void RemoveMutex(IMediaPlayer other)
        {
            _mutexControllers.Remove(other);
        }

        public virtual void Schedule(IVideoContext context, BaseMediaPlayerData mediaPlayerData)
        {
            if (mediaPlayerData == null)
            {
                Debug.LogError("clip is null");
                return;
            }
            LazyInit();
            // var now = Time.time;
            var curr = _playQueue.Last;
            while (curr != null)
            {
                var comb = curr.Value;
                // if (
                //     comb.ComboCount < maxComboCount
                //     && comb.VideoClip == videoClip
                //     && comb.Context.IsCombo(context)
                // )
                // {
                //     // 合并
                //     comb.ComboCount++;
                //     return;
                // }
                if (context.IsCombinable(comb.Items, comb.TotalScalarValue))
                {
                    // 合并
                    comb.Add(context);
                    SortPlayQueueByWeight(_playQueue);
                    return;
                }
                curr = curr.Previous;
            }

            // Combo failed
            EnqueueNewPlay(context, mediaPlayerData);
        }

        private void SortPlayQueueByWeight(LinkedList<PlayData> _playQueue)
        {
            if (_playQueue == null || _playQueue.First == null || _playQueue.First.Next == null)
                return;

            var current = _playQueue.First.Next;
            while (current != null)
            {
                var next = current.Next;
                var temp = current.Value;

                var node = current.Previous;
                while (node != null && node.Value.TotalWeightValue > temp.TotalWeightValue)
                {
                    node = node.Previous;
                }

                if (node == null)
                {
                    _playQueue.Remove(current);
                    _playQueue.AddFirst(current);
                }
                else if (node == current.Previous)
                {
                    // No need to move
                }
                else
                {
                    _playQueue.Remove(current);
                    _playQueue.AddAfter(node, current);
                }

                current = next;
            }
        }

        public void StopCurrent()
        {
            throw new System.NotImplementedException("有需求再实现 ...");
        }

        /// <summary>
        /// 停止并取消所有播放任务
        /// </summary>
        [Button]
        public virtual void StopAndUnscheduleAll()
        {
#if UNITY_EDITOR
            if (!Application.IsPlaying(gameObject))
            {
                return;
            }
#endif
            if (!_isInited)
            {
                return;
            }
            StopPlaying();
            if (_playQueue.Count > 0)
            {
                // 回收内存
                foreach (var combo in _playQueue)
                {
                    _playDataPool.Return(combo);
                }
                _playQueue.Clear();
            }
        }

        /// <summary>
        /// 新播放任务入队列
        /// </summary>
        protected void EnqueueNewPlay(
            IVideoContext context,
            BaseMediaPlayerData mediaPlayerData
        )
        {
            var newCombo = _playDataPool.Get();
            newCombo.videoData = mediaPlayerData;
            // newCombo.Context = context;
            // newCombo.VideoClip = videoClip;
            // newCombo.AudioClip = audioClip;
            // newCombo.ComboCount = 1;
            newCombo.Add(context);

            _playQueue.AddFirst(newCombo);
            SortPlayQueueByWeight(_playQueue);
        }

        protected void LazyInit()
        {
            if (_isInited)
            {
                return;
            }

            // void ResetPlayData(PlayData comb)
            // {
            //     // comb.VideoClip = null;
            //     // comb.AudioClip = null;
            //     // // comb.Context = null;
            //     // comb.Items.Clear();
            //     // comb.TotalScalarValue = 0;
            //     // // comb.ComboCount = 0;

            // }

            _playDataPool ??= new Pool<PlayData>(
                () => new PlayData(),
                null,
                PlayData.Reset,
                PlayData.Reset,
                100
            );
            _isInited = true;
        }

        /// <summary>
        /// 播放下一个
        /// </summary>
        /// <returns>没有任务返回false</returns>
        protected virtual bool PlayNext()
        {
            var tail = _playQueue.Last;
            if (tail != null)
            {
                var combo = tail.Value;
                _playQueue.RemoveLast();
                Play(combo, combo.videoData);
            }
            return false;
        }


        protected virtual void Play(PlayData combo, BaseMediaPlayerData mediaPlayerData)
        {
            _cursor = combo;

            IsPlayerStarted = true;
            _videoPrepareTime = Time.unscaledTime;
            PlayVideo(mediaPlayerData);
            StopAudio();
            onVideoWillPlay?.Invoke(this, _cursor.Items, _cursor.TotalScalarValue);
        }

        private void StopPlaying()
        {
            if (!_isInited)
            {
                return;
            }
            if (IsPlayerStarted)
            {
                _lastPlayEndTime = Time.time;

                StopPlayingProcess();

                _cursor = null;

                IsPlayerStarted = false;
            }
        }

        /// <summary>
        /// 播放完成
        /// </summary>
        /// <param name="source"></param>
        protected virtual void OnVideoLoopPointReached()
        {
            if (IsPlayerStarted)
            {
                var totalScalarValue = _cursor.TotalScalarValue;
                var items = _cursor.Items;
                StopPlaying();

                onVideoPlayComplete?.Invoke(this, items, totalScalarValue);
            }
            else
            {
                Debug.LogError("IsPlayingOrWillPlay is false");
            }
        }

        //[Title("默认播放倍速")]
        //public float DefaultControlSpeed = 1.2f;
        protected virtual void OnVideoPrepareCompleted()
        {
            if (IsPlayerStarted)
            {
                var prepareTime = Time.unscaledTime - _videoPrepareTime;
                //  Debug.Log($"Elapsed time {prepareTime:F3}s");
                // FIXME: lich: 从这个节点开始, 才能控制播放速度

                ////==temp
                //float videoCount = _playQueue.Count;
                //float controlSpeed = 1;
                //if (videoCount > 0)
                //{
                //    //todo:数值临时这么写回头将参数公开
                //    if (videoCount <= 8) controlSpeed = 1;
                //    else if (videoCount <= 15) controlSpeed = 1.3f;
                //    else if (videoCount <= 25) controlSpeed = 1.6f;
                //    else controlSpeed = 2f;
                //}
                //ChangeMediaPlaySpeed(controlSpeed * Time.timeScale);
            }
        }

        protected virtual void OnVideoStarted()
        {
            if (IsPlayerStarted)
            {
                //var startedTime = Time.unscaledTime - _videoPrepareTime;
                //Debug.Log($"Elapsed time {startedTime:F3}s");

                if (_cursor.videoData != null)
                {
                    PlayAudio(_cursor.videoData);
                }

                onVideoPlayStarted?.Invoke(this, _cursor.Items, _cursor.TotalScalarValue);
            }
        }

        protected virtual void LateUpdate()
        {
            if (IsPlayerStarted)
                return;
            if (playInterval > 0.0f && Time.time - _lastPlayEndTime < playInterval)
            {
                return;
            }
            if (_mutexControllers.Count == 0)
                PlayNext();
        }

        protected virtual void OnDestroy()
        {
#if UNITY_EDITOR
            if (!Application.IsPlaying(gameObject))
            {
                return;
            }
#endif
            StopAndUnscheduleAll();
        }

        protected abstract void StopPlayingProcess();

        protected abstract void PlayVideo(BaseMediaPlayerData mediaPlayerData);

        protected abstract void PlayAudio(BaseMediaPlayerData mediaPlayerData);

        protected abstract void StopVideo();

        protected abstract void StopAudio();

        public abstract void ChangeMediaPlaySpeed(float targetSpeed);
    }
}
